
#include "AppTask.h"
#include "a7128.h"
#include "rf_sensor.h"
#include <app_bridged_device.h>
#include <blemesh_bridge.h>
#include "uart_util.h"
#include "radio.h"
#include "rom/gpio.h"

//#define DisableSensor 1

#define TAG_RF       "RF_SENSOR"
#define RF_TASK_PRIORITY			(6)

typedef enum{
    NO_SENSOR,
    ONEWAY_SENSOR,
    TWOWAY_SENSOR,
} sensor_type_t;


SemaphoreHandle_t spiSemaphore = NULL;
BaseType_t rf_read_task_handle;
TaskHandle_t rf_sensor_task_handle = NULL;

static uint32_t success_cnt=0;
static uint32_t failed_cnt=0;
static uint32_t error1_cnt=0,error2_cnt=0;

static bool isPairing=0;
static sensor_type_t sensor_type;

static MqttData_t  MqttData;
using namespace esp_matter;

uint32_t get_rf_sensor_error1_cnt(void)
{
	return error1_cnt;
}

uint32_t get_rf_sensor_error2_cnt(void)
{
	return error2_cnt;
}

void set_rf_sensor_MqttData(MqttData_t *data)
{
	MqttData = *data;
}

MqttData_t* get_rf_sensor_MqttData(void)
{
	return &MqttData;
}

void set_rf_sensor_mode(bool pairing)
{
	if(sensor_type == ONEWAY_SENSOR)
		isPairing = pairing;	
	else{
		isPairing = pairing;	
		set_pairing_mode(pairing);
        ESP_LOGW("sendor debug","yuezheng.gao set sensor flag = %d", isPairing);
        }
}
bool get_rf_sensor_mode(void)
{
	return isPairing;
}

uint32_t get_sensor_success_cnt(void)
{
	return success_cnt;
}
uint32_t get_sensor_failed_cnt(void)
{
	return failed_cnt;
}

void IRAM_ATTR spi_isr_handler(void* arg) {
    // notify the SPI status changed
	xSemaphoreGiveFromISR(spiSemaphore, NULL);
}

void app_rf_sensor_process(uint8_t *buf, uint32_t length)
{
    ESP_LOGI(TAG_RF, "app_rf_sensor_process length= 0x%" PRIX32 " ", length);
	uint8_t* buffer = (uint8_t*) pvPortMalloc(length);
	if(buffer){
		memcpy(buffer, (uint8_t*)buf, length);
		if(GetAppTask().PostRfActionRequest(length, buffer)==ESP_FAIL){
			 vPortFree(buffer);
		     buffer = NULL;
			}
	}else{
		ESP_LOGE(TAG_RF, "app_rf_sensor pvPortMalloc error");
	}
}

void rf_read_task(void* arg) 
{
	uint8_t buf[16];
	static uint8_t buf_temp[16];
    size_t cycle = 0;	
	rf_signal_raw_t data,last_data;
    ESP_LOGI(TAG_RF,"-------RF read task started----------\r\n");

	for(;;) {
		if(sensor_type == ONEWAY_SENSOR){
			if(xSemaphoreTake(spiSemaphore,portMAX_DELAY) == pdTRUE) {
				memset(buf,0x0,sizeof(buf));
				if(rf_a7123ReceiveData_prc(buf, sizeof(buf))){
					success_cnt++;
					if(memcmp(buf, buf_temp, sizeof(buf))!=0){
						memcpy(buf_temp, buf, sizeof(buf));
						app_rf_sensor_process(buf, sizeof(buf));
					}
				}else{
					failed_cnt++;
					ESP_LOGE(TAG_RF, "Read A7123 error!");
				}
				cycle++;
				if(cycle==20){
					cycle=0;
					vTaskDelay(50 / portTICK_RATE_MS); //Sleep 50ms for every 20 signals
				}
			}
		}
		else if(sensor_type == TWOWAY_SENSOR){
			if(xQueueReceive(rf_msg_queue,&data,portMAX_DELAY)){
				if(data.is_error){
                    ESP_LOGE(TAG_RF, "xQueueReceive(rf_msg_queue err");

                    failed_cnt++;

				}
				else{
                    ESP_LOGE(TAG_RF, "xQueueReceive(rf_msg_queue success");

                    success_cnt++;
                    // 调试门磁配对，偶现需要闭合一次门磁才能成功的问题

                    printf("    _data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02lx %02x %02x %02x \r\n",
                           data.packet.header,
                           data.packet.pkg_no,
                           data.packet.packet_type,
                           data.packet.flag,
                           data.packet.sensor_type,
                           data.packet.sensor_id.num[0],
                           data.packet.sensor_id.num[1],
                           data.packet.sensor_id.num[2],
                           data.packet.event_status,
                           data.packet.data6,
                           data.packet.data7,
                           data.packet.data8,
                           data.packet.data9,
                           data.packet.data10,
                           data.packet.data11, 
                           data.packet.crc, 
                           data.packet.sn_count, 
                           data.packet.sensor_ver.num[0],
                           data.packet.sensor_ver.num[1],
                           data.packet.sensor_ver.num[2]
                           );

                    printf("last_data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02lx %02x %02x %02x \r\n",
                           last_data.packet.header,
                           last_data.packet.pkg_no,
                           last_data.packet.packet_type,
                           last_data.packet.flag,
                           last_data.packet.sensor_type,
                           last_data.packet.sensor_id.num[0],
                           last_data.packet.sensor_id.num[1],
                           last_data.packet.sensor_id.num[2],
                           last_data.packet.event_status,
                           last_data.packet.data6,
                           last_data.packet.data7,
                           last_data.packet.data8,
                           last_data.packet.data9,
                           last_data.packet.data10,
                           last_data.packet.data11, 
                           last_data.packet.crc, 
                           last_data.packet.sn_count, 
                           last_data.packet.sensor_ver.num[0],
                           last_data.packet.sensor_ver.num[1],
                           last_data.packet.sensor_ver.num[2]
                           );


                    if((memcmp(&last_data, &data, sizeof(rf_signal_raw_t))!=0)){
                        ESP_LOGE("sendor debug", "memcmp(&last_data, &data, sizeof(rf_signal_raw_t))!=0 is Paring mode = %d",get_rf_sensor_mode());
						memcpy(&last_data,&data,sizeof(rf_signal_raw_t));
						app_rf_sensor_process((uint8_t*)&data.packet, sizeof(rf_sensor_packet_t));

					}
                    else
                    {
                        //修复门磁重复绑定时，需要开关一次门磁才能成功绑定的bug <在绑定状态下，不验证与前一次的消息是否相同>
                        if(get_rf_sensor_mode())
                        {
                            app_rf_sensor_process((uint8_t *)&data.packet, sizeof(rf_sensor_packet_t));
                        }
                        ESP_LOGE("sendor debug", "memcmp(&last_data, &data, sizeof(rf_signal_raw_t)) ==   0  is Paring mode = %d",get_rf_sensor_mode());
                    }
				}
			}
		}
	}
}

void ble_diagnose_init(void){
	gpio_pad_select_gpio(21);
	gpio_set_direction(21, GPIO_MODE_OUTPUT);
	gpio_set_level(21, 0);
}

void sensor_type_init(void)
{
	if(memcmp(get_hub_id(),"PGH260",6)==0)
		sensor_type = TWOWAY_SENSOR;
	else if(memcmp(get_hub_id(),"PGH270",6)==0)
		sensor_type = ONEWAY_SENSOR;	
	else
		sensor_type = NO_SENSOR;
#ifdef DisableSensor	
	sensor_type = NO_SENSOR;
#endif
    ESP_LOGI(TAG_RF, "sensor_type_init = %d", sensor_type);
}

void rf_sensor_init(void)
{
	sensor_type_init();
	if(sensor_type == NO_SENSOR)
		return;
	else if(sensor_type == ONEWAY_SENSOR){
		rf_a7128_init();
		if(spiSemaphore==NULL)
			spiSemaphore = xSemaphoreCreateBinary();	
		gpio_set_intr_type((gpio_num_t)GPIO_STATUS, GPIO_INTR_NEGEDGE);	
		gpio_install_isr_service(0);
		gpio_isr_handler_add((gpio_num_t)GPIO_STATUS, spi_isr_handler, NULL);
	}
	else if(sensor_type == TWOWAY_SENSOR){
		// gpio_pad_select_gpio(21);
		// gpio_set_direction(21, GPIO_MODE_OUTPUT);
		// gpio_set_level(21, 0);

		//ESP_LOGE(TAG_RF, "Skip RF_Init for testing...");
		ESP_LOGE(TAG_RF, "Starting RF_Init for ...");
		RF_Init();	
		if(rf_msg_queue==NULL)
			rf_msg_queue=xQueueCreate(20,sizeof(rf_signal_raw_t));
	}
    rf_read_task_handle = xTaskCreate(rf_read_task, "rf_read_task", 2560, NULL, RF_TASK_PRIORITY, &rf_sensor_task_handle);
}

void rf_sensor_task_delete(void)
{
	if(sensor_type == NO_SENSOR)
		return;
	else{
		vTaskDelete(rf_sensor_task_handle);
		if(sensor_type == TWOWAY_SENSOR)	
			rf_task_delete();
	}
}

void rf_sensor_task_create(void)
{
	if(sensor_type == NO_SENSOR)
		return;
	else{
	    rf_read_task_handle = xTaskCreate(rf_read_task, "rf_read_task", 2560, NULL, RF_TASK_PRIORITY, &rf_sensor_task_handle);
		if(sensor_type == TWOWAY_SENSOR)	
			rf_task_create();		
	}
}

void RfReceiveEventHandler(AppEvent * aEvent)
{
	app_bridged_device_t *device;
	uint8_t espnow_macaddr[6]={0};
	app_bridged_device_info_t bridged_device_info; 
	memset(&bridged_device_info, 0, sizeof(app_bridged_device_info_t));
	if(aEvent->RfEvent.buf){	
		ESP_LOGI(TAG_RF, "RfReceiveEventHandler");
		esp_log_buffer_hex(TAG_RF, aEvent->RfEvent.buf, aEvent->RfEvent.len);
		rf_sensor_packet_t * p = (rf_sensor_packet_t *)aEvent->RfEvent.buf;
		//if(p->sensor_type == RF_DOOR)
		{
			memcpy(&espnow_macaddr[3],	reinterpret_cast<uint8_t *>(&p->sensor_id), sizeof(rf_sensor_id_t));			
			if(isPairing){				
				device = app_bridge_get_device_by_device_uuid((uint8_t *)MqttData.hubCommandRequest.bindSensor.did);
				if(device){
					if(p->sensor_type==MqttData.hubCommandRequest.bindSensor.bind_rf_type){
						strcpy((char*)bridged_device_info.sensor_did,MqttData.hubCommandRequest.bindSensor.did);	
						strcpy((char*)bridged_device_info.sensor_hubmc,MqttData.hubCommandRequest.bindSensor.hub_mc);
						snprintf((char*)bridged_device_info.sensor_id, 8, "%02x%02x%02x",espnow_macaddr[3], espnow_macaddr[4], espnow_macaddr[5]);
						bridged_device_info.sensor_type = MqttData.hubCommandRequest.bindSensor.bind_rf_type;
						if( ENABLE_HOMEKIT_SENSOR )
							blemesh_bridge_match_bridged_door_sensor(espnow_macaddr,bridged_device_info);						
						else
							ESP_LOGE(TAG_RF, "Pairing mode, but homekit sensor is disabled");
						GetAppTask().AppScheduleWork(PublishBindSensorResponse, reinterpret_cast<intptr_t>(&MqttData));  
						set_rf_sensor_mode(false);
					}
				}
			}			
			device = app_bridge_get_device_by_espnow_macaddr(espnow_macaddr);			
			if(device){
				device->dev_info.last_update_time = get_timestamp_ms();
				if(device->dev_info.is_online==false){
					device->dev_info.is_online = true;
					if( ENABLE_HOMEKIT_SENSOR )
						DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(device));					
					else
						ESP_LOGE(TAG_RF, "Sensor offline, but homekit sensor is disabled");

				}				
				if(device->dev_info.sensor_status != p->event_status)
				{
					if(((device->dev_info.sensor_status & 0x01)!=(p->event_status & 0x01))||((device->dev_info.sensor_status & 0x02)!=(p->event_status & 0x02))){	
						device->dev_info.sensor_status = p->event_status;							
						if (ENABLE_HOMEKIT_SENSOR)
							DeviceLayer::PlatformMgr().ScheduleWork(UpdateDoorSensorAttribute, reinterpret_cast<intptr_t>(device));
						else
							ESP_LOGE(TAG_RF, "Sensor status changed, but homekit sensor is disabled");
					}
					device->dev_info.sensor_status = p->event_status;	
					device->dev_info.last_change_time = get_timestamp_ms();				
					GetAppTask().AppScheduleWork(sync_ds_status_with_lock, reinterpret_cast<intptr_t>(device));  					
					GetAppTask().AppScheduleWork(PublishDoorSensorStatus,  reinterpret_cast<intptr_t>(device)); 
				}
			}
		}

		vPortFree(aEvent->RfEvent.buf);
		aEvent->RfEvent.buf = NULL;
	}
}



void UpdateDoorSensorAttribute(intptr_t context)
{
	app_bridged_device_t *device;
	uint16_t endpointId;
	device = (app_bridged_device_t *)context;
	endpointId = esp_matter::endpoint::get_id(device->dev->endpoint);
		
	node_t *node = node::get();
	endpoint_t *endpoint = endpoint::get(node, endpointId);
	cluster_t *cluster = cluster::get(endpoint, BooleanState::Id);
	attribute_t *attribute = attribute::get(cluster, BooleanState::Attributes::StateValue::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
    if(device->dev_info.sensor_status & 0x01){
		val.val.b = false; //open;
    }
	else if(device->dev_info.sensor_status & 0x02){
		val.val.b = true; //close;
	}	
	attribute::update(endpointId, BooleanState::Id, BooleanState::Attributes::StateValue::Id, &val);	
}

void ProcessSensorHeartbeat(uint8_t      * id)
{
	
	uint8_t id_str[8]={0};
	app_bridged_device_t *device;	
	hex_to_str(id_str, id, sizeof(rf_sensor_id_t));
	ESP_LOGE(TAG_RF, "ProcessSensorHeartbeat:%s",id_str);
	device = app_bridge_get_sensor_by_sensor_id(id_str);
	if(device){
		device->dev_info.last_update_time = get_timestamp_ms();		
		ESP_LOGE(TAG_RF, "Found Sensor");
		if(device->dev_info.is_online==false){
			device->dev_info.is_online = true;
			DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(device));					
		}
	}
}

void CheckRFsensorState(void)
{
	if(sensor_type == TWOWAY_SENSOR){
		if(sensor_handshake_flag)
		{
			if(sensor_handshake_count)
				sensor_handshake_count--;
		}
		if((sensor_handshake_count==0)&&(sensor_handshake_flag))
		{
			sensor_handshake_flag = 0;
			//Set_Frequece_Init();
			SetRfStaus(RF_STATE_ERROR);
			ESP_LOGE(TAG_RF,"-----set to ferquence 0\n");
		}
		if(RF_system.g_nTxTimeout>0)
		{
			RF_system.g_nTxTimeout--;
			if(RF_system.g_nTxTimeout==0)
			{
				SetRfStaus(RF_STATE_TX_TIMEOUT);//SetBit_RFEventGroup();
			}
		}
	}
}

void CheckRFsensorTimeout(void)
{
	if(sensor_type == TWOWAY_SENSOR){
		if(is_mqtt_connected())	{
			app_bridged_device_t *current_device = app_bridge_get_bridged_device_list();
			if(IsTimeSynchronized()==false)
				return;			
			uint64_t now = get_timestamp_ms();
			static bool offline=0;
			while (current_device) {
				if ((current_device->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_LOCKLY) && current_device->dev){
					 if((current_device->dev->persistent_info.device_type_id==ESP_MATTER_CONTACT_SENSOR_DEVICE_TYPE_ID)&&(strcmp(current_device->dev_info.sensor_id,"FFFFFF")!=0))
					{
						 if((current_device->dev_info.last_update_time) &&\
							(now - current_device->dev_info.last_update_time >5*3600*1000)){
							uint8_t rf_state = get_rf_state();
							rf_state &= 0x0f;
							ESP_LOGE(TAG_RF,"CheckRFsensorTimeout");
							if(0!=get_current_chal()){
								error1_cnt++;
								SetRfStaus(RF_STATE_ERROR);
								ESP_LOGE(TAG_RF,"----- rf ferquence error\n");		
							}
							if(rf_state != 5){
								error2_cnt++;
								SetRfStaus(RF_STATE_TX_TIMEOUT);
								ESP_LOGE(TAG_RF,"-----rf state error \n");	
							}
						 }
					}
				}
				current_device = current_device->next;
			}
		}
	}
}

